home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1995 / MacHack 1995.toast / Presentations / Presentations ’91 / MPW Stand-Alone Libraries / UMultiSegSA.incl.p < prev    next >
Text File  |  1991-03-02  |  30KB  |  1,108 lines

  1. { A useful type definitions for routines that manipulate    }
  2. { the main jumptable and gather information about segments. }
  3.  
  4. TYPE
  5.     IntArray = ARRAY [0..maxInt] OF Integer;
  6.     IArrPtr = ^IntArray;
  7.     IArrHdl = ^IArrPtr;
  8.  
  9.     SegmentInfo = RECORD
  10.         firstProc:    Integer;    { offset of first proc in main jump table }
  11.         numJTProcs:    Integer;    { number of procs in the main jump table }
  12.     END;
  13.     
  14.     
  15.     
  16. {--------------------------------------------------------------------------------------------------}
  17.  
  18. {$S TInit}
  19.  
  20. PROCEDURE TMultiSegSA.IMultiSegSA(aFile: FileSpec;
  21.                             mainType: ResType;
  22.                             mainID: Integer;
  23.                             mainName: StringHandle;
  24.                             otherType: ResType);
  25.     VAR
  26.         aStrHdl:    StringHandle;
  27.         
  28.     BEGIN
  29.         fSrcRefNum    := 0;
  30.         fDestRefNum    := 0;
  31.         fFileSpec    := aFile;
  32.         fMainType    := mainType;
  33.         fMainID        := mainID;
  34.         fOtherType    := otherType;
  35.         
  36.         IF (mainName <> NIL) THEN
  37.             BEGIN
  38.             aStrHdl        := mainName;
  39.             FailOSErr(HandToHand(Handle(aStrHdl)));
  40.             fMainName    := aStrHdl;
  41.             END
  42.         ELSE
  43.             fMainName    := NIL;
  44.         
  45.         { These must be initialzed to their "empty" table sizes or havoc will ensue }
  46.         fJTSize        := 4;
  47.         fCtorJTSize    := 4;
  48.         fDtorJTSize    := 4;
  49.         fSegTabSize    := 4;
  50.         
  51.         { Standalone code size is the above plus size of BSR, and multiseg type }
  52.         fSACodeSize    := 8 + fJTSize + fCtorJTSize + fDtorJTSize + fSegTabSize;
  53.     END;
  54.     
  55. {--------------------------------------------------------------------------------------------------}
  56.  
  57. {$S TRes}
  58.  
  59. { Attempt to open the source resource fork and create the destination resource }
  60. { fork. Delete the destination resource fork if it exists prior to attempting }
  61. { to create it. }
  62.  
  63. PROCEDURE TMultiSegSA.OpenFiles;
  64.  
  65.     VAR
  66.         tempName:    Str255;
  67.         fi:            FailInfo;
  68.         err:        OSErr;
  69.  
  70.     PROCEDURE HdlFailure(error: Integer; message: LongInt);
  71.         BEGIN
  72.             IF (fSrcRefNum <> 0) AND (fSrcRefNum <> -1) THEN CloseResFile(fSrcRefNum);
  73.             IF (fDestRefNum <> 0) AND (fDestRefNum <> -1) THEN CloseResFile(fDestRefNum);
  74.             tempName := concat('An error occured while opening the file ',tempName);
  75.             gMakeSA.Stop(tempName); 
  76.         END;
  77.  
  78.     BEGIN
  79.         CatchFailures(fi, HdlFailure);
  80.  
  81.         tempName := fFileSpec.fileName^^;
  82.         tempName := concat(tempName, kSASuffix);
  83.  
  84.         fDestRefNum := OpenResFile(tempName);        { open destination file }
  85.         IF (fDestRefNum = -1) OR (fDestRefNum = 0) THEN
  86.             BEGIN
  87.                 err := ResError;
  88.                 IF (err = resFNotFound) OR (err = fnfErr) THEN
  89.                     BEGIN
  90.                         CreateResFile(tempName);        { create destination file }
  91.                         FailResError;
  92.                         fDestRefNum := OpenResFile(tempName);
  93.                         FailResError;
  94.                     END
  95.                 ELSE
  96.                     FailResError;
  97.             END;
  98.         
  99.         tempName := fFileSpec.fileName^^;
  100.         fSrcRefNum := OpenResFile(tempName);        { open source file }
  101.         IF (fSrcRefNum = -1) OR (fSrcRefNum = 0) THEN FailResError;
  102.         
  103.         Success(fi);
  104.     END;
  105.     
  106. {--------------------------------------------------------------------------------------------------}
  107.  
  108. {$S TRes}
  109.  
  110. PROCEDURE TMultiSegSA.CloseSourceFile;
  111.  
  112.     BEGIN
  113.         CloseResFile(fSrcRefNum);    { We're done with the source file }
  114.     END;
  115.  
  116. {--------------------------------------------------------------------------------------------------}
  117.  
  118. {$S TRes}
  119.  
  120. PROCEDURE TMultiSegSA.CloseDestinationFile;
  121.  
  122.     BEGIN
  123.         CloseResFile(fDestRefNum);    { We're done with the destination file }
  124.     END;
  125.  
  126. {--------------------------------------------------------------------------------------------------}
  127.  
  128. {$S TRes}
  129.  
  130. PROCEDURE TMultiSegSA.ShowNumericalProgress(aStr: Str255; aLong: LongInt);
  131.  
  132.     VAR
  133.         tempStr:    Str255;
  134.         
  135.     BEGIN
  136.         NumToString(aLong, tempStr);
  137.         tempStr := Concat(aStr, tempStr);
  138.         gMakeSA.DoShowProgress(tempStr);
  139.     END;
  140.  
  141. {--------------------------------------------------------------------------------------------------}
  142.  
  143. {$S TRes}
  144.  
  145. PROCEDURE TMultiSegSA.ShowTextProgress(aStr: Str255);
  146.  
  147.     BEGIN
  148.         gMakeSA.DoShowProgress(aStr);
  149.     END;
  150.  
  151. {--------------------------------------------------------------------------------------------------}
  152.  
  153. {$S TRes}
  154.  
  155. PROCEDURE TMultiSegSA.ReplaceSegment(theRsrc: Handle; theType: ResType; theID: Integer; VAR theName: Str255);
  156.  
  157.     VAR
  158.         tempHdl:    Handle;
  159.         tempAttrs:    Integer;
  160.         
  161. BEGIN
  162.     SetResLoad(FALSE);                        { if the rsrc exists, dispose of it }
  163.     tempHdl := NIL;
  164.     tempHdl := Get1Resource(theType, theID);
  165.     IF (tempHdl <> NIL) THEN
  166.         BEGIN
  167.             tempAttrs := GetResAttrs(tempHdl);
  168.             tempAttrs := BAND(tempAttrs, $FFF7);
  169.             SetResAttrs(tempHdl, tempAttrs);    { Turn off the protect bit }
  170.             RmveResource(tempHdl);
  171.             FailResError;
  172.             DisposHandle(tempHdl);
  173.         END;
  174.     SetResLoad(TRUE);
  175.         
  176.     AddResource(theRsrc, theType, theID, theName);
  177.     FailResError;
  178.     WriteResource(theRsrc);
  179.     FailResError;
  180. END;        
  181.  
  182.  
  183. {--------------------------------------------------------------------------------------------------}
  184.  
  185. {$S TRes}
  186.  
  187. PROCEDURE TMultiSegSA.AddMainSegment(VAR saCode: Handle);
  188.  
  189.     VAR
  190.         fi:            FailInfo;
  191.         tempName:    Str255;
  192.         
  193.     PROCEDURE HdlAddFailure(error: Integer; message: LongInt);
  194.         BEGIN
  195.             SetResLoad(TRUE);
  196.             IF (saCode <> NIL) THEN DisposHandle(saCode);
  197.             UseResFile(fSrcRefNum);            { reset to our src rsrc file }
  198.             CloseResFile(fDestRefNum);
  199.         END;
  200.         
  201.     PROCEDURE HdlUpdateFailure(error: Integer; message: LongInt);
  202.         BEGIN
  203.             IF (saCode <> NIL) THEN ReleaseResource(saCode);
  204.             UseResFile(fSrcRefNum);            { reset to our src rsrc file }
  205.             CloseResFile(fDestRefNum);
  206.         END;
  207.         
  208.     BEGIN
  209.         CatchFailures(fi, HdlAddFailure);
  210.         UseResFile(fDestRefNum);            { set to our dest rsrc file before adding resource }
  211.         IF (fMainName <> NIL) THEN
  212.             tempName := fMainName^^
  213.         ELSE
  214.             tempName := '';
  215.         ReplaceSegment(saCode, fMainType, fMainID, tempName);
  216.         Success(fi);
  217.         
  218.         CatchFailures(fi, HdlUpdateFailure);
  219.         UpdateResFile(fDestRefNum);
  220.         FailResError;
  221.         ReleaseResource(saCode);
  222.         UseResFile(fSrcRefNum);                { reset to our src rsrc file }
  223.         Success(fi);
  224.     END;
  225.     
  226. {--------------------------------------------------------------------------------------------------}
  227.  
  228. {$S TRes}
  229.  
  230. PROCEDURE TMultiSegSA.AddOtherCodeSegments(saCode: Handle; otherSegType: ResType);
  231.     
  232.     TYPE
  233.         SACodeType = (sepSeg, mainSeg, jtSeg, ctordtorSeg);
  234.         
  235.         CodeDesc = RECORD
  236.             codeID:        Integer;
  237.             codeName:    Str255;
  238.             codeSize:    LongInt;
  239.             rsrcType:    ResType;
  240.             codeType:    SACodeType;
  241.         END;
  242.         
  243.     VAR
  244.         theCode:    Handle;
  245.         i, newID:    Integer;
  246.         theCount:    Integer;
  247.         fi:            FailInfo;
  248.         codeArray:    TDynamicArray;
  249.         aCodeDesc:    CodeDesc;
  250.         segInfo:    SegmentInfo;
  251.     
  252.     FUNCTION ForThisItemDo(index: ArrayIndex): BOOLEAN;
  253.         VAR
  254.             aCodeDesc: CodeDesc;
  255.         BEGIN
  256.             codeArray.GetElementsAt(index, @aCodeDesc, 1);
  257.             ShowNumericalProgress('CodeID ', aCodeDesc.codeID);
  258.             ShowNumericalProgress('Index  ', index);
  259.             ForThisItemDo := FALSE;
  260.         END;
  261.     
  262.     PROCEDURE AddCodeInfo(VAR aCodeDesc: CodeDesc; aCodeArray: TDynamicArray);
  263.         VAR
  264.             lower, upper, k:    ArrayIndex;
  265.             arraySize:    ArrayIndex;
  266.             temp:        CodeDesc;
  267.         BEGIN
  268.             lower := 1;
  269.             arraySize := aCodeArray.GetSize;
  270.             upper := arraySize;
  271.             REPEAT
  272.                 k := (lower + upper) DIV 2;
  273.                 aCodeArray.GetElementsAt(k, @temp, 1);
  274.                 IF (aCodeDesc.codeID < temp.codeID) THEN
  275.                     upper := k - 1
  276.                 ELSE
  277.                     lower := k + 1;
  278.             UNTIL ((aCodeDesc.codeID = temp.codeID) OR (lower > upper));
  279.             
  280.             IF (aCodeDesc.codeID = temp.CodeID) THEN
  281.                 aCodeArray.InsertElementsBefore(k, @aCodeDesc, 1)
  282.             ELSE
  283.                 aCodeArray.InsertElementsBefore(arraySize + 1, @aCodeDesc, 1);
  284.         END;
  285.     
  286.     
  287.     PROCEDURE CollateCodeInfo(count: Integer; aCodeArray: TDynamicArray);
  288.         VAR
  289.             aCodeDesc:    CodeDesc;
  290.             theCode:    Handle;
  291.             dummy:        ArrayIndex;
  292.             theID:        Integer;
  293.             theType:    ResType;
  294.             theName:    Str255;
  295.             i:            Integer;
  296.         BEGIN
  297.             SetResLoad(FALSE);
  298.             { Collect code resources info, and sort by ID }
  299.             FOR i := 1 TO count DO
  300.                 BEGIN
  301.                     theCode := NIL;
  302.                     theCode := Get1IndResource('CODE', i);
  303.                     FailNilResource(theCode);
  304.                     GetResInfo(theCode, theID, theType, theName);
  305.                     FailResError;
  306.                     
  307.                     WITH aCodeDesc DO
  308.                         BEGIN
  309.                             codeID := theID;
  310.                             codeName := theName;
  311.                             codeSize := SizeResource(theCode);
  312.                             rsrcType := theType;
  313.                             
  314.                             IF (theID = 0) THEN
  315.                                 codeType := jtSeg
  316.                             ELSE IF (theName = kCtorDtorSeg) THEN
  317.                                 codeType := ctordtorSeg
  318.                             ELSE IF (WillBeMerged(theID, theName)) THEN
  319.                                 codeType := mainSeg
  320.                             ELSE
  321.                                 codeType := sepSeg;
  322.                         END;
  323.                     ReleaseResource(theCode);
  324.                     AddCodeInfo(aCodeDesc, aCodeArray);
  325.                 END;
  326. {•}            dummy := aCodeArray.EachElementDoTil(ForThisItemDo, kIterateForward);
  327.             SetResLoad(TRUE);
  328.         END;
  329.         
  330.     PROCEDURE HdlAddFailure(error: Integer; message: LongInt);
  331.         BEGIN
  332.             { Free the code segment }
  333.             IF (theCode <> NIL) THEN DisposHandle(theCode);
  334.             
  335.             SetResLoad(TRUE);                { CollateCodeInfo turns it off }
  336.             UpdateResFile(fDestRefNum);        { force the rsrc map to be updated }
  337.             UseResFile(fSrcRefNum);            { reset to our src rsrc file }
  338.             codeArray.Free;                    { free the code elements }
  339.         END;
  340.         
  341.  
  342.     BEGIN
  343.         theCount := Count1Resources('CODE');
  344.         IF (theCount <= 0) THEN Failure(resNotFound, 0);
  345.                 
  346.         New(codeArray);
  347.         FailNil(codeArray);
  348.         codeArray.IDynamicArray(theCount, SizeOf(CodeDesc));
  349.         
  350.         CatchFailures(fi, HdlAddFailure);
  351.         
  352.         CollateCodeInfo(theCount, codeArray);
  353.         
  354.         { Move the non-main code resources into the new file }
  355.         { Make sure we start at ID = 1. The main entry point }
  356.         { must be in ID = 0.                                 }
  357.         newID := 1;
  358.         FOR i := 1 TO theCount DO
  359.             BEGIN
  360.                 codeArray.GetElementsAt(i, @aCodeDesc, 1);
  361.                 theCode := NIL;
  362.                 theCode := Get1Resource('CODE', aCodeDesc.codeID);
  363.                 FailNilResource(theCode);
  364.                 { Have we found a code segment to be added as a seperate segment, maybe }
  365.                 IF (aCodeDesc.codeType = sepSeg) THEN
  366.                     BEGIN
  367.                         ShowNumericalProgress('Adding segment ', aCodeDesc.codeID);
  368.                         { rsrc mgr will think it belongs elsewhere if not detached }
  369.                         DetachResource(theCode);
  370.                         UseResFile(fDestRefNum);
  371.                         ReplaceSegment(theCode, otherSegType, newID, aCodeDesc.codeName);
  372.                         UseResFile(fSrcRefNum);
  373.                         { Get segment info and then modify it's SA jumptable entry }
  374.                         BlockMove(theCode^, @segInfo, SizeOf(SegmentInfo));
  375.                         AdjustMainJTable(saCode, 0, aCodeDesc.codeID, newID, segInfo.firstProc, segInfo.numJTProcs);
  376.                         ShowNumericalProgress('Added segment as ', newID);
  377.                         newID := newID + 1;
  378.                     END;
  379.                 ReleaseResource(theCode);
  380.             END;
  381.         UpdateResFile(fDestRefNum);        { force the rsrc map to be updated }
  382.         codeArray.Free;                    { Release the storage for the array }
  383.         Success(fi);
  384.     END;
  385.     
  386. {--------------------------------------------------------------------------------------------------}
  387.  
  388. {$S TRes}
  389.  
  390.  
  391. PROCEDURE TMultiSegSA.CalcJTSize(rawJTSize: LongInt);
  392.  
  393.     VAR
  394.         tempLong:    LongInt;
  395.         
  396.     BEGIN
  397.         IF (rawJTSize = 0) THEN
  398.             tempLong := 4
  399.         ELSE
  400.             tempLong := 4 + ((rawJTSize - kCode0Hdr) DIV kJTDivisor);
  401.         ShowNumericalProgress('Main jumptable size = ', tempLong);
  402.         fJTSize := tempLong;
  403.     END;
  404.  
  405. {--------------------------------------------------------------------------------------------------}
  406.  
  407. {$S TRes}
  408.  
  409. PROCEDURE TMultiSegSA.CalcCtorJTSize(theSize: LongInt);
  410.  
  411.     VAR
  412.         tempLong:    LongInt;
  413.         
  414.     BEGIN
  415.         IF (theSize = 0) THEN
  416.             tempLong := 4
  417.         ELSE
  418.             tempLong := 4 + ((theSize - kCodeHdr) DIV 2);
  419.         ShowNumericalProgress('Ctor jumptable size = ', tempLong);
  420.         fCtorJTSize := tempLong;
  421.     END;
  422.  
  423. {--------------------------------------------------------------------------------------------------}
  424.  
  425. {$S TRes}
  426.  
  427. PROCEDURE TMultiSegSA.CalcDtorJTSize(theSize: LongInt);
  428.  
  429.     VAR
  430.         tempLong:    LongInt;
  431.         
  432.     BEGIN
  433.         IF (theSize = 0) THEN
  434.             tempLong := 4
  435.         ELSE
  436.             tempLong := 4 + ((theSize - kCodeHdr) DIV 2);
  437.         ShowNumericalProgress('Dtor jumptable size = ', tempLong);
  438.         fDtorJTSize := tempLong;
  439.     END;
  440.  
  441. {--------------------------------------------------------------------------------------------------}
  442.  
  443. {$S TRes}
  444.  
  445. PROCEDURE TMultiSegSA.CalcSegTableSize(theCount: Integer; hasCtorDtorJT: Boolean);
  446.  
  447.     VAR
  448.         tempSize:    LongInt;
  449.         
  450.     BEGIN
  451.         IF hasCtorDtorJT THEN            { if there is a static ctor/dtor jtable then }
  452.             tempSize := theCount - 2    { don't include it & code 0 it in our SegTable }
  453.         ELSE
  454.             tempSize := theCount - 1;    { otherwise leave out only code 0 }
  455.             
  456.         IF (theCount <= 0) THEN
  457.             tempSize := 4
  458.         ELSE
  459.             tempSize := 4 + (tempSize * 4);
  460.         ShowNumericalProgress('Segment table size = ', tempSize);
  461.         fSegTabSize := tempSize;
  462.     END;
  463.  
  464. {--------------------------------------------------------------------------------------------------}
  465.  
  466. {$S TRes}
  467.  
  468. FUNCTION TMultiSegSA.GetNumJTEntries: LongInt;
  469.  
  470.     VAR
  471.         tempLong:    LongInt;
  472.         
  473.     BEGIN
  474.         tempLong := (GetJTSize - 4) DIV 4;
  475.         ShowNumericalProgress('Number of main jumptable entries = ', tempLong);
  476.         GetNumJTEntries := tempLong;
  477.     END;
  478.  
  479. {--------------------------------------------------------------------------------------------------}
  480.  
  481. {$S TRes}
  482.  
  483. FUNCTION TMultiSegSA.GetNumCtorJTEntries: LongInt;
  484.  
  485.     VAR
  486.         tempLong:    LongInt;
  487.         
  488.     BEGIN
  489.         tempLong := (GetCtorJTSize - 4) DIV 2;
  490.         ShowNumericalProgress('Number of static ctor jumptable entries = ', tempLong);
  491.         GetNumCtorJTEntries := tempLong;
  492.     END;
  493.  
  494. {--------------------------------------------------------------------------------------------------}
  495.  
  496. {$S TRes}
  497.  
  498. FUNCTION TMultiSegSA.GetNumDtorJTEntries: LongInt;
  499.  
  500.     VAR
  501.         tempLong:    LongInt;
  502.         
  503.     BEGIN
  504.         tempLong := (GetDtorJTSize - 4) DIV 2;
  505.         ShowNumericalProgress('Number of static dtor jumptable entries = ', tempLong);
  506.         GetNumDtorJTEntries := tempLong;
  507.     END;
  508.  
  509. {--------------------------------------------------------------------------------------------------}
  510.  
  511. {$S TRes}
  512.  
  513. FUNCTION TMultiSegSA.GetNumSegTableEntries: LongInt;
  514.  
  515.     VAR
  516.         tempLong:    LongInt;
  517.         
  518.     BEGIN
  519.         tempLong := (GetSegTableSize - 4) DIV 4;
  520.         ShowNumericalProgress('Number of segment table entries = ', tempLong);
  521.         GetNumSegTableEntries := tempLong;
  522.     END;
  523.  
  524. {--------------------------------------------------------------------------------------------------}
  525.  
  526. {$S TRes}
  527.  
  528. FUNCTION TMultiSegSA.GetJTSize: LongInt;
  529.  
  530.     BEGIN
  531.         GetJTSize := fJTSize;
  532.     END;
  533.  
  534. {--------------------------------------------------------------------------------------------------}
  535.  
  536. {$S TRes}
  537.  
  538. FUNCTION TMultiSegSA.GetCtorJTSize: LongInt;
  539.  
  540.     BEGIN
  541.         GetCtorJTSize := fCtorJTSize;
  542.     END;
  543.  
  544. {--------------------------------------------------------------------------------------------------}
  545.  
  546. {$S TRes}
  547.  
  548. FUNCTION TMultiSegSA.GetDtorJTSize: LongInt;
  549.  
  550.     BEGIN
  551.         GetDtorJTSize := fDtorJTSize;
  552.     END;
  553.  
  554. {--------------------------------------------------------------------------------------------------}
  555.  
  556. {$S TRes}
  557.  
  558. FUNCTION TMultiSegSA.GetSegTableSize: LongInt;
  559.  
  560.     BEGIN
  561.         GetSegTableSize := fSegTabSize;
  562.     END;
  563.  
  564. {--------------------------------------------------------------------------------------------------}
  565.  
  566. {$S TRes}
  567.  
  568. FUNCTION TMultiSegSA.GetSACodeSize: LongInt;
  569.  
  570.     BEGIN
  571.         GetSACodeSize := fSACodeSize;
  572.     END;
  573.  
  574. {--------------------------------------------------------------------------------------------------}
  575.  
  576. {$S TRes}
  577. { We're only concerned with CODE 1 here. All other normal code segments }
  578. { will not be merged into the standalone code resources. Thus they are "filtered out" }
  579. { by this method. This method must be overridden if you need to change which }
  580. { code segments are merged into the final standalone CODE segment. }
  581.  
  582. FUNCTION TMultiSegSA.WillBeMerged(theID: Integer; theName: Str255): BOOLEAN;
  583.  
  584.     BEGIN
  585.         IF (theID = 1) THEN { We are only concerned with CODE 1 }
  586.             WillBeMerged := TRUE
  587.         ELSE
  588.             WillBeMerged := FALSE;
  589.     END;
  590.     
  591. {--------------------------------------------------------------------------------------------------}
  592.  
  593. {$S TRes}
  594.  
  595. PROCEDURE TMultiSegSA.CalcSACodeSize;
  596.  
  597.     VAR
  598.         theCode:        Handle;
  599.         i:                Integer;
  600.         theCount:        Integer;
  601.         theID:            Integer;
  602.         theType:        ResType;
  603.         theName:        Str255;
  604.         theSize:        LongInt;
  605.         fi:                FailInfo;
  606.         hasCtorDtorJT:    Boolean;
  607.         
  608.     PROCEDURE HdlFailure(error: Integer; message: LongInt);
  609.     
  610.         VAR
  611.             tempName:    Str255;
  612.             tempLong:    LongInt;
  613.             
  614.         BEGIN
  615.             tempName := fFileSpec.fileName^^;
  616.             CASE error OF
  617.                 resNotFound:
  618.                     WriteLn(kErrorMarker, tempName, ' does not contain CODE resources.');
  619.                 OTHERWISE
  620.                     WriteLn(kErrorMarker, tempName, ' error occured while scanning CODE resources.'); 
  621.             END;
  622.         END;
  623.         
  624.     BEGIN
  625.         CatchFailures(fi, HdlFailure);
  626.         SetResLoad(FALSE);    { We only want info on the rsrc's. DONT LOAD THEM! }
  627.         
  628.         { The first thing in the SACode is the BSR instruction. }
  629.         fSACodeSize := kBSRSize;
  630.         
  631.         { Now add in the size of the segment's resource type }
  632.         fSACodeSize := fSACodeSize + kSegTypeSize;
  633.         
  634.         theCount := Count1Resources('CODE');
  635.         IF (theCount <= 0) THEN Failure(resNotFound, 0);
  636.         
  637.         hasCtorDtorJT := FALSE;        { assume there are no static ctor and dtors }
  638.         
  639.         { Sum the CODE segment sizes. However, watch out for special segments, and }
  640.         { don't add the sizes of anything other than code 0 and code 1 }
  641.         FOR i := 1 TO theCount DO
  642.             BEGIN
  643.                 theCode := NIL;
  644.                 theCode := Get1IndResource('CODE', i);
  645.                 FailNilResource(theCode);
  646.                 theSize := SizeResource(theCode);
  647.                 GetResInfo(theCode, theID, theType, theName);
  648.                 ReleaseResource(theCode);
  649.                 
  650.                 IF (theID = 0) THEN                        { Found jump table }
  651.                     BEGIN
  652.                         CalcJTSize(theSize);
  653.                     END
  654.                 ELSE IF (theName = kCtorDtorSeg) THEN    { Found CtorDtor jump table }
  655.                     BEGIN
  656.                         CalcCtorJTSize(theSize);
  657.                         CalcDtorJTSize(theSize);
  658.                         hasCtorDtorJT := TRUE;
  659.                     END
  660.                 ELSE IF WillBeMerged(theID, theName) THEN    { Found a code segment we'll merge }
  661.                     fSACodeSize := fSACodeSize + theSize - kCodeHdr;
  662.             END;
  663.         
  664.         CalcSegTableSize(theCount, hasCtorDtorJT);
  665.         
  666.         theSize := fSACodeSize + GetJTSize + GetCtorJTSize + GetDtorJTSize + GetSegTableSize;
  667.         ShowNumericalProgress('Estimated standalone size = ', theSize);
  668.         IF (theSize > maxInt) THEN
  669.             gMakeSA.Stop('Main code segement exceeds 32K');
  670.         fSACodeSize := theSize;
  671.  
  672.         SetResLoad(TRUE);
  673.         Success(fi);
  674.     END;
  675.     
  676. {--------------------------------------------------------------------------------------------------}
  677.  
  678. {$S TRes}
  679.  
  680. FUNCTION TMultiSegSA.AllocateSACode(theSize: LongInt): Handle;
  681.  
  682.     VAR
  683.         aHandle:    Handle;
  684.         
  685.     BEGIN
  686.         aHandle := NIL;
  687.         aHandle := NewHandle(theSize);
  688.         FailNIL(aHandle);
  689.         AllocateSACode := aHandle;
  690.     END;
  691.  
  692. {--------------------------------------------------------------------------------------------------}
  693.  
  694. {$S TRes}
  695.  
  696. FUNCTION TMultiSegSA.GetCode0: Handle;
  697.  
  698.     VAR
  699.         aHandle:    Handle;
  700.         
  701.     BEGIN
  702.         aHandle := NIL;
  703.         aHandle := Get1Resource('CODE', 0);
  704.         FailNilResource(aHandle);
  705.         GetCode0 := aHandle;
  706.     END;
  707.  
  708. {--------------------------------------------------------------------------------------------------}
  709.  
  710. {$S TRes}
  711.  
  712. FUNCTION TMultiSegSA.GetCtorDtorJT: Handle;
  713.  
  714.     VAR
  715.         aHandle:    Handle;
  716.         
  717.     BEGIN
  718.         aHandle := NIL;
  719.         aHandle := Get1NamedResource('CODE', kCtorDtorSeg);
  720.         { *** This can fail because not every piece of code has *** }
  721.         { *** a CtorDtor jumptable. Thus we can't call FailNil! *** }
  722.         IF (ResError <> noErr) THEN
  723.             aHandle := NIL;
  724.         GetCtorDtorJT := aHandle;
  725.     END;
  726.  
  727. {--------------------------------------------------------------------------------------------------}
  728.  
  729. {$S TRes}
  730.  
  731. PROCEDURE TMultiSegSA.BuildBSR(code0, saCode: Handle; VAR saPos: LongInt);
  732.  
  733.     VAR
  734.         theBSRinst:        LongInt;    { The full BSR $XXXX instruction goes here }
  735.         theEntryPt:        Integer;    { 1st entry in original main jumptable has offset to MAIN }
  736.         theOffset:        Integer;    { Our calculated offset to main entry point }
  737.  
  738.     BEGIN
  739.         { offset to main entry point of SARuntime is 1st entry in main jumptable }
  740.         BlockMove(Ptr(ORD(code0^)+kCode0Hdr), @theEntryPt, 2);
  741.  
  742.         { move the BSR instruction into the standalone and set it to BSR to MAIN }
  743.         theBSRinst := BSL(kBSRCode, 16);
  744.         theOffset := kSegTypeSize + GetJTSize + GetCtorJTSize + GetDtorJTSize + GetSegTableSize;
  745.         theOffset := theOffset + theEntryPt + 2;
  746.         theBSRinst := theBSRinst + theOffset;
  747.         BlockMove(@theBSRinst, Ptr(ORD(saCode^)+saPos), kBSRSize);
  748.         saPos := saPos + kBSRSize;
  749.         ShowNumericalProgress('BSR offset to main proc is: ', theOffset);
  750.         ShowNumericalProgress('BSR to main proc ends at: ', saPos);
  751.     END;
  752.  
  753. {--------------------------------------------------------------------------------------------------}
  754.  
  755. {$S TRes}
  756.  
  757. PROCEDURE TMultiSegSA.BuildSegType(segType: ResType; saCode: Handle; VAR saPos: LongInt);
  758.  
  759.     BEGIN
  760.         { move the BSR instruction into the standalone and set it to BSR to MAIN }
  761.         BlockMove(@segType, Ptr(ORD(saCode^)+saPos), kSegTypeSize);
  762.         ShowNumericalProgress('Offset to segment restype is: ', saPos);
  763.         saPos := saPos + kSegTypeSize;
  764.     END;
  765.  
  766. {--------------------------------------------------------------------------------------------------}
  767.  
  768. {$S TRes}
  769.  
  770. PROCEDURE TMultiSegSA.BuildJumpTable(code0, saCode: Handle; VAR saPos: LongInt);
  771.  
  772.     TYPE
  773.         JTEntry = RECORD
  774.             offset:        Integer;
  775.             move:        Integer;
  776.             segNum:        Integer;
  777.             loadSeg:    Integer;
  778.         END;
  779.         
  780.     VAR
  781.         numJTEntries:    LongInt;
  782.         code0Pos:        LongInt;
  783.         theEntry:        JTEntry;
  784.         i:                Integer;
  785.         
  786.     BEGIN
  787.         { move the numJTEntries into the standalone }
  788.         numJTEntries := GetNumJTEntries;
  789.         BlockMove(@numJTEntries, Ptr(ORD(saCode^)+saPos), kNumJTSize);
  790.         saPos := saPos + kNumJTSize;
  791.         
  792.         code0Pos := kCode0Hdr;
  793.         FOR i := 0 TO numJTEntries-1 DO
  794.             BEGIN
  795.                 BlockMove(Ptr(ORD(code0^)+code0Pos), @theEntry, SizeOf(JTEntry));
  796.                 BlockMove(@theEntry.offset, Ptr(ORD(saCode^)+saPos), 2);
  797.                 BlockMove(@theEntry.segNum, Ptr(ORD(saCode^)+saPos+2), 2);
  798.                 code0Pos := code0Pos + SizeOf(JTEntry);
  799.                 saPos := saPos + 4;
  800.             END;
  801.         ShowNumericalProgress('Main jump table ends at: ', saPos);
  802.     END;
  803.  
  804. {--------------------------------------------------------------------------------------------------}
  805.  
  806. {$S TRes}
  807.  
  808. PROCEDURE TMultiSegSA.BuildCtorJTable(theJT, saCode: Handle; VAR saPos: LongInt);
  809.  
  810.     VAR
  811.         saveSAPos:    LongInt;
  812.         theJTPos:    LongInt;
  813.         numEntries:    LongInt;    { number of Ctor JT entries we actually find }
  814.         count:        Integer;    { number of Ctor JT entries we think there are }
  815.         theEntry:    Integer;
  816.         i:            Integer;
  817.         
  818.     BEGIN
  819.         saveSAPos := saPos;                { remember this for when we stuff # JT entries }
  820.         count := GetNumCtorJTEntries;    { This was determined earlier }
  821.         numEntries := 0;                { we'll assume that there are null entries }
  822.         theJTPos := kCodeHdr;            { skip over code header }
  823.         saPos := saPos + kNumJTSize;    { leave room at top for num of JT entries }
  824.  
  825.         IF (theJT = NIL) THEN            { Whoops! Handle this as best we can... }
  826.             count := 0;
  827.             
  828.         { Remember that ctor entries are every other _even_ word offset after code header }
  829.         FOR i := 0 TO count-1 DO
  830.             BEGIN
  831.                 BlockMove(Ptr(ORD(theJT^)+theJTPos), @theEntry, 2);
  832.                 IF (theEntry <> 0) THEN                    { skip over null entry }
  833.                     BEGIN
  834.                         BlockMove(@theEntry, Ptr(ORD(saCode^)+saPos), 2);
  835.                         saPos := saPos + ((i + 1) * 2);    { bump offset up one word }
  836.                         numEntries := numEntries + 1;
  837.                     END;
  838.                 theJTPos := theJTPos + ((i + 1) * 2);    { bump offset up one word }
  839.             END;
  840.         
  841.         { Now move in the number of JT entries at top of table }
  842.         BlockMove(@numEntries, Ptr(ORD(saCode^)+saveSAPos), kNumJTSize);
  843.         ShowNumericalProgress('Ctor table ends at: ', saPos);
  844.     END;
  845.  
  846. {--------------------------------------------------------------------------------------------------}
  847.  
  848. {$S TRes}
  849.  
  850. PROCEDURE TMultiSegSA.BuildDtorJTable(theJT, saCode: Handle; VAR saPos: LongInt);
  851.  
  852.     VAR
  853.         saveSAPos:    LongInt;
  854.         theJTPos:    LongInt;
  855.         numEntries:    LongInt;    { number of Dtor JT entries we actually find }
  856.         count:        Integer;    { number of Dtor JT entries we think there are }
  857.         theEntry:    Integer;
  858.         i:            Integer;
  859.         
  860.     BEGIN
  861.         saveSAPos := saPos;                { remember this for when we stuff # JT entries }
  862.         count := GetNumDtorJTEntries;    { This was determined earlier }
  863.         
  864.         { skip all the way to last Dtor entry. }
  865.         { Remember that dtor entries are every other _odd_ word offset after code header }
  866.         theJTPos := kCodeHdr + ((count-1) * 2) + 2;
  867.         
  868.         numEntries := 0;                { we'll assume that there are null entries }
  869.         saPos := saPos + kNumJTSize;    { leave room at top for num of JT entries }
  870.  
  871.         IF (theJT = NIL) THEN            { Whoops! Handle this as best we can... }
  872.             count := 0;
  873.             
  874.         FOR i := count-1 DOWNTO 0 DO
  875.             BEGIN
  876.                 BlockMove(Ptr(ORD(theJT^)+theJTPos), @theEntry, 2);
  877.                 IF (theEntry <> 0) THEN                { skip over null entry }
  878.                     BEGIN
  879.                         BlockMove(@theEntry, Ptr(ORD(saCode^)+saPos), 2);
  880.                         saPos := saPos + ((i + 1) * 2);    { bump offset down one word }
  881.                         numEntries := numEntries + 1;
  882.                     END;
  883.                 theJTPos := theJTPos - ((i + 1) * 2);    { bump offset down one word }
  884.             END;
  885.         
  886.         { Now move in the number of JT entries at top of table }
  887.         BlockMove(@numEntries, Ptr(ORD(saCode^)+saveSAPos), kNumJTSize);
  888.         ShowNumericalProgress('Dtor table ends at: ', saPos);
  889.     END;
  890.  
  891. {--------------------------------------------------------------------------------------------------}
  892.  
  893. {$S TRes}
  894.  
  895. PROCEDURE TMultiSegSA.BuildSegTable(saCode: Handle; VAR saPos: LongInt);
  896.  
  897.     TYPE
  898.         LongArray = ARRAY [0..maxInt] OF LongInt;
  899.         LArrPtr = ^LongArray;
  900.         LArrHdl = ^LArrPtr;
  901.     
  902.     VAR
  903.         i:            Integer;
  904.         count:        Integer;
  905.         laPtr:        LArrPtr;
  906.         numEntries:    LongInt;
  907.         laOffset:    LongInt;
  908.  
  909.     BEGIN
  910.         count := GetNumSegTableEntries;
  911.         numEntries := count;
  912.         laOffset := saPos;
  913.         BlockMove(@numEntries, Ptr(ORD(saCode^)+laOffset), kNumJTSize);
  914.         laOffset := laOffset + kNumJTSize;
  915.         
  916.         HLock(saCode);
  917.         laPtr := LArrHdl(saCode)^;
  918.         laPtr := LArrPtr(ORD(laPtr) + laOffset);
  919.         FOR i := 0 TO count-1 DO
  920.             laPtr^[i] := 0;
  921.         saPos := saPos + GetSegTableSize;
  922.         HUnlock(saCode);
  923.         ShowNumericalProgress('Segment table ends at: ', saPos);
  924.     END;
  925.  
  926. {--------------------------------------------------------------------------------------------------}
  927.  
  928. {$S TRes} 
  929.  
  930. PROCEDURE TMultiSegSA.AdjustMainJTable(saCode: Handle;
  931.                                     segOffset:    LongInt;
  932.                                     oldSegNum, newSegNum, jtOffset, numEntries: Integer);
  933.     VAR
  934.         i:                Integer;
  935.         iaPtr:            IArrPtr;
  936.         jtEntry:        Integer;
  937.         segEntry:        Integer;
  938.         nextOffset:        Integer;
  939.         myJTOffset:        Integer;
  940.         fi:                FailInfo;
  941.         
  942.     PROCEDURE HdlFailure(error: Integer; message: LongInt);
  943.     
  944.         VAR
  945.             shortStr:    Str15;
  946.             tempStr:    Str255;
  947.             
  948.         BEGIN
  949.             IF (saCode <> NIL) THEN HUnlock(saCode);
  950.             NumToString(error, tempStr);
  951.             shortStr := tempStr;
  952.             NumToString(message, tempStr);
  953.             tempStr := concat('Original segment was ', shortStr, ' whereas segment being merged is ', tempStr);
  954.             WriteLn(Diagnostic,
  955.                 'Segment number mismatch occured while adjusting main jump table.');
  956.             WriteLn(Diagnostic, tempStr);
  957.         END;
  958.         
  959.     BEGIN
  960.         CatchFailures(fi, HdlFailure);
  961.         HLock(saCode);
  962.         myJTOffset := jtOffset DIV 4;    { original jumptable entry is 8 bytes, divide by 4 }
  963.         iaPtr := IArrHdl(saCode)^;
  964.         iaPtr := IArrPtr(ORD(iaPtr) + kJTStart);    { point to beginning of SA jumptable }
  965.         FOR i := 0 TO numEntries-1 DO
  966.             BEGIN
  967.                 nextOffset := myJTOffset + (i * 2);
  968.                 jtEntry := iaPtr^[nextOffset];
  969.                 segEntry := iaPtr^[nextOffset+1];
  970.                 IF (segEntry <> oldSegNum) THEN
  971.                     Failure(segEntry, oldSegNum);
  972.                 iaPtr^[nextOffset] := jtEntry + segOffset;
  973.                 iaPtr^[nextOffset+1] := newSegNum;    { Set the segment number to the new value }
  974.             END;
  975.         HUnlock(saCode);
  976.         Success(fi);
  977.     END;
  978.  
  979. {--------------------------------------------------------------------------------------------------}
  980.  
  981. {$S TRes}
  982.  
  983. PROCEDURE TMultiSegSA.Merge1Segment(segNum: Integer; theCode: Handle; codeSize: LongInt;
  984.                                 saCode: Handle; VAR saPos: LongInt);
  985.  
  986.     VAR
  987.         segInfo:    SegmentInfo;
  988.         mySize:        LongInt;
  989.         
  990.     BEGIN
  991.         mySize := codeSize - kCodeHdr;    { strip off the header }
  992.         
  993.         { Get the segment info }
  994.         BlockMove(theCode^, @segInfo, SizeOf(SegmentInfo));
  995.         
  996.         { Move the segment into standalone code, but not code header }
  997.         BlockMove(Ptr(ORD(theCode^)+kCodeHdr),
  998.                     Ptr(ORD(saCode^)+saPos), mySize);
  999.         
  1000.         { We are only going to adjust the segment that the main entry }
  1001.         { point is in. That is _always_ segment zero!                 }
  1002.         AdjustMainJTable(saCode, saPos, segNum, 0, segInfo.firstProc, segInfo.numJTProcs);
  1003.         saPos := saPos + mySize;
  1004.     END;
  1005.  
  1006. {--------------------------------------------------------------------------------------------------}
  1007.  
  1008. {$S TRes}
  1009.  
  1010. PROCEDURE TMultiSegSA.MergeCodeSegments(saCode: Handle; VAR saPos: LongInt);
  1011.  
  1012.     VAR
  1013.         theCode:    Handle;
  1014.         theSize:    LongInt;
  1015.         
  1016.     BEGIN
  1017.         { merge in CODE 1 first! }
  1018.         theCode := NIL;
  1019.         theCode := Get1Resource('CODE', 1);
  1020.         FailNilResource(theCode);
  1021.         theSize := SizeResource(theCode);
  1022.         Merge1Segment(1, theCode, theSize, saCode, saPos);
  1023.         ReleaseResource(theCode);
  1024.         ShowNumericalProgress('Code 1 ends at: ', saPos);
  1025.         
  1026.         { We only merge CODE 1 for multi-segment stand alone code.             }
  1027.         { The remaining CODE segments are left as code segments, though        }
  1028.         { we should consider renaming them.(?)  Also, because we leave         }
  1029.         { them alone, we don't have to adjust the jump table entries for these }
  1030.         { segments! (not often that the work is already done for you...)       }
  1031.     END;
  1032.  
  1033. {--------------------------------------------------------------------------------------------------}
  1034.  
  1035. {$S TRes}
  1036.  
  1037. PROCEDURE TMultiSegSA.BuildStandAlone;
  1038.  
  1039.     VAR
  1040.         code0:        Handle;
  1041.         ctordtorJT:    Handle;
  1042.         saCode:        Handle;
  1043.         pos:        LongInt;
  1044.         fi:            FailInfo;
  1045.  
  1046.     PROCEDURE HdlFailure(error: Integer; message: LongInt);
  1047.         BEGIN
  1048.             IF (saCode <> NIL) THEN DisposHandle(saCode);
  1049.             IF (code0 <> NIL) THEN ReleaseResource(code0);
  1050.             IF (ctordtorJT <> NIL) THEN ReleaseResource(ctordtorJT);
  1051.         END;
  1052.         
  1053.     BEGIN
  1054.         code0 := NIL;
  1055.         saCode := NIL;
  1056.         pos := 0;
  1057.  
  1058.         CatchFailures(fi, HdlFailure);
  1059.  
  1060.         saCode := AllocateSACode(GetSACodeSize);
  1061.  
  1062.         code0 := GetCode0;
  1063.         BuildBSR(code0, saCode, pos);
  1064.         BuildSegType(fOtherType, saCode, pos);
  1065.         BuildJumpTable(code0, saCode, pos);
  1066.         ReleaseResource(code0);
  1067.         code0 := NIL;
  1068.         
  1069.         ctordtorJT := NIL;
  1070.         ctordtorJT := GetCtorDtorJT;
  1071.         BuildCtorJTable(ctordtorJT, saCode, pos);
  1072.         BuildDtorJTable(ctordtorJT, saCode, pos);
  1073.         IF (ctordtorJT <> NIL) THEN        { If we found the CtorDtor jumptable }
  1074.             ReleaseResource(ctordtorJT);
  1075.         
  1076.         BuildSegTable(saCode, pos);
  1077.  
  1078.         MergeCodeSegments(saCode, pos);
  1079.         ShowNumericalProgress('Final size of standalone is: ', pos);
  1080.  
  1081.         AddOtherCodeSegments(saCode, fOtherType);
  1082.  
  1083.         SetHandleSize(saCode, pos);        { Shorten handle size to actual length used }
  1084.         AddMainSegment(saCode);
  1085.         CloseSourceFile;
  1086.         CloseDestinationFile;
  1087.         Success(fi);
  1088.         ShowTextProgress('Done.');
  1089.     END;
  1090.     
  1091. {--------------------------------------------------------------------------------------------------}
  1092.  
  1093. {$S TRes}
  1094. { Take a file, extract the various needed CODE resources and massage }
  1095. { them into the single standalone code resource. }
  1096.  
  1097. PROCEDURE TMultiSegSA.DoIt;
  1098.  
  1099.     BEGIN
  1100.         OpenFiles;
  1101.  
  1102.         CalcSACodeSize;
  1103.         
  1104.         BuildStandAlone;
  1105.     END;
  1106.  
  1107. {--------------------------------------------------------------------------------------------------}
  1108.